package com.mamba.microservice.http;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Copyright ©2020 360jinrong All Rights Reserved
 * 请添加类/接口的说明：
 *
 * @Package: com.qihoo.finance.utils.http.crawler
 * @author: fangjin
 * @date: 2020年04月15日 15时38分
 */
public class HttpCommon {
    protected static final Logger logger = LoggerFactory.getLogger(HttpCommon.class);
    private static final String HTTPS_PREFIX = "https://";

    private static final int RETRY_TIME = 3;

    /**
     * Http请求方式
     */
    private enum HttpMethod {
        /**
         * GET请求
         */
        GET,
        /**
         * POST请求
         */
        POST
    }


    public static HttpResponseContent doGet(String url) {
        return doGet(url, "utf-8", null);
    }

    public static HttpResponseContent doGet(String url, List<Cookie> cookies) {
        return doGet(url, "utf-8", cookies);
    }


    public static HttpResponseContent doGet(String url, String urlEncoding, List<Cookie> cookies) {
        return sendRequest(url, urlEncoding, cookies, HttpMethod.GET, null, null);
    }


    public static HttpResponseContent doPost(String url) {
        return doPost(url, null);
    }

    public static HttpResponseContent doPost(String url, Map<String, String> params) {
        return doPost(url, params, new HashMap<>());
    }

    public static HttpResponseContent doPost(String url, Map<String, String> params, List<Cookie> cookies) {
        return doPost(url, params, new HashMap<>(), cookies);
    }

    public static HttpResponseContent doPost(String url, Map<String, String> params, Map<String, String> headers) {
        return doPost(url, params, headers, null);
    }

    public static HttpResponseContent doPost(String url, Map<String, String> params, Map<String, String> headers, List<Cookie> cookies) {
        return sendRequest(url, "utf-8", cookies, HttpMethod.POST, params, headers);
    }


    private static HttpResponseContent sendRequest(String url,
                                                   String urlEncoding,
                                                   List<Cookie> cookies,
                                                   HttpMethod httpMethod,
                                                   Map<String, String> params,
                                                   Map<String, String> headers) {

        if (StringUtils.isEmpty(url)) {
            throw new IllegalArgumentException("传入的url不能为空");
        }
        BasicCookieStore basicCookieStore = new BasicCookieStore();
        if (CollectionUtils.isNotEmpty(cookies)) {
            for (Cookie cookie : cookies) {
                basicCookieStore.addCookie(cookie);
            }
        }
        CloseableHttpClient client = createClientByParams(url, basicCookieStore);

        HttpRequestBase request = null;
        CloseableHttpResponse response = null;
        HttpResponseContent httpResponseContent = new HttpResponseContent();
        int requestNum = 0;
        do {
            try {
                request = newRequest(httpMethod, url, urlEncoding, params);
                setHeaders(request, headers);
                request.setConfig(RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build());

                response = client.execute(request);
                httpResponseContent = httpResponse(response);
                httpResponseContent.setCookies(basicCookieStore.getCookies());

            } catch (Exception e) {
                logger.error("请求url:{}出错", url, e);
                httpResponseContent.setStatusCode(-1);
            }
            requestNum++;
        } while (httpResponseContent.getStatusCode() == -1 && requestNum <= RETRY_TIME);
        return httpResponseContent;
    }

    private static CloseableHttpClient createClientByParams(String url, BasicCookieStore basicCookieStore) {
        HttpClientComponentBuilder builder = new HttpClientComponentBuilder();
        return url.startsWith(HTTPS_PREFIX) ? builder.createHttpsClient().setCookies(basicCookieStore).build()
                : builder.createHttpClient().setCookies(basicCookieStore).build();
    }


    private static HttpResponseContent httpResponse(CloseableHttpResponse response) {
        HttpResponseContent httpResponseContent = new HttpResponseContent();
        try {
            httpResponseContent.setStatusCode(response.getStatusLine().getStatusCode());
            httpResponseContent.setResponseResult(EntityUtils.toString(response.getEntity()));
        } catch (Exception e) {
            httpResponseContent.setStatusCode(500);
        }
        return httpResponseContent;
    }


    /**
     * 创建request
     *
     * @param httpMethod
     * @param url
     * @param urlEncoding
     * @param params
     * @return
     * @throws Exception
     */
    private static HttpRequestBase newRequest(HttpMethod httpMethod, String url, String urlEncoding, Map<String, String> params) throws Exception {
        if (HttpMethod.GET == httpMethod) {
            HttpRequestBase request = new HttpGet(url);
            return request;
        } else if (HttpMethod.POST == httpMethod) {
            HttpPost httpPost = new HttpPost(url);
            List<NameValuePair> nvBodyList = transferParamsToNvs(params);
            httpPost.setEntity(new UrlEncodedFormEntity(nvBodyList, urlEncoding));
            return httpPost;
        }
        return null;
    }

    /**
     * 参数
     *
     * @param params
     * @return
     */
    private static List<NameValuePair> transferParamsToNvs(Map<String, String> params) {
        List<NameValuePair> nameValuePairs = new ArrayList<>();
        if (params == null) {
            return nameValuePairs;
        }
        for (Map.Entry<String, String> param : params.entrySet()) {
            BasicNameValuePair nameValuePair = new BasicNameValuePair(param.getKey(), param.getValue());
            nameValuePairs.add(nameValuePair);
        }
        return nameValuePairs;
    }

    private static void setHeaders(HttpRequestBase request, Map<String, String> headers) {
        if (headers == null) {
            return;
        }
        for (Map.Entry<String, String> header : headers.entrySet()) {
            request.addHeader(header.getKey(), header.getValue());
        }
    }


}
